package offical.coroutine

import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

/**
 * 组合挂起函数
 */


suspend fun doSomething1(): Int {
    delay(500L)
    return 200
}

suspend fun doSomething2(): Int {
    delay(1000L)
    return 300
}

//fun main() = runBlocking {
//
////    val measureTimeMillis = measureTimeMillis {
////
////        //默认顺序调用，时间叠加
////        val val1 = doSomething1()
////        val val2 = doSomething2()
////
////        println("answer is ${val1 + val2}")
////    }
//
////    val measureTimeMillis = measureTimeMillis {
////
////        //并发顺序，同时调用
////        //async 就类似于 launch。它启动了一个单独的协程
////        //launch 返回一个 Job 并且不附带任何结果值，
////        // 而 async 返回一个 Deferred —— 一个轻量级的非阻塞 future， 这代表了一个将会在稍后提供结果的 promise
////        val val1 = async { doSomething1() }
////        val val2 = async { doSomething2() }
////
////        println("answer is ${val1.await() + val2.await()}")
////    }
//
//    //惰性启动的 async
//    //只有结果通过 await 获取的时候协程才会启动，或者在 Job 的 start 函数调用的时候
//    val measureTimeMillis = measureTimeMillis {
//
//        val val1 = async (start = CoroutineStart.LAZY){ doSomething1() }
//        val val2 = async (start = CoroutineStart.LAZY){ doSomething2() }
//
//        //只是在 println 中调用 await，而没有在单独的协程中调用 start，这将会导致顺序行为
//        val2.start()
//        println("answer is ${val1.await() + val2.await()}")
//    }
//
//    println("complete time is $measureTimeMillis")
//}

//不推荐，无法控制异常
//fun main() {
//    val measureTimeMillis = measureTimeMillis {
//
//        val val1 = GlobalScope.async { doSomething1() }
//        val val2 = GlobalScope.async { doSomething2() }
//        runBlocking {
//            println("answer is ${val1.await() + val2.await()}")
//        }
//    }
//
//    println("complete time is $measureTimeMillis")
//}

/**
 * async 结构化并发
 */

//如果其中一个子协程（即 two）失败，第一个 async 以及等待中的父协程都会被取消
fun main() = runBlocking<Unit> {
    try {
        failedConcurrentSum()
    } catch(e: ArithmeticException) {
        println("Computation failed with ArithmeticException")
    }
}

suspend fun failedConcurrentSum(): Int = coroutineScope {
    val one = async<Int> {
        try {
            delay(Long.MAX_VALUE) // 模拟一个长时间的运算
            42
        } finally {
            println("First child was cancelled")
        }
    }
    val two = async<Int> {
        println("Second child throws an exception")
        throw ArithmeticException()
    }
    one.await() + two.await()
}